/**
 * @widoc $.fn.initSelNum
 * @namespace comp
 * @depends dataFormat/$.dataFormat
 * @des 初始化 numbox
 * @type function
 * @demo initSelNum/demo0 数字输入框
 * @param {object} opts 配置参数
 * @param {string} opts.name 组件生成的文本框的 name 值，定义后不可修改。
 * @param {boolean=} opts.enable 初始化时是否启用，默认为 true。
 * @param {boolean=} opts.allowEmpty 是否允许为 ''，默认为 false。
 * @param {boolean=} opts.allowFloat 是否支持浮点数，默认为 false。
 * @param {number=} opts.maxVal 控件支持的最大值，默认为正无穷。
 * @param {number=} opts.minVal 控件支持的最小值，默认为负无穷。
 * @param {''|number=} opts.value 初始化时的值。取值的顺序：minVal -> maxVal -> 0(allowEmpty=false) 或 ''（allowEmpty=true）
 * @param {number=} opts.step 每次增减的数值，默认为 1。
 * @param {function(val)} opts.onChange 值变化时的回调方法。
 * @return {object} rtn 接口对象
 * @rtn {function} rtn.setVal(val) 为文本框赋值
 *   - val {number|string}
 * @rtn {function} rtn.getVal() 获取当前值
 * @rtn {function} rtn.setEnable(enable) 禁用/启用
 *   - enable {boolean}
 * @rtn {function} rtn.fReset(cusOpts) 重置
 *   - cusOpts {object} 同初始化参数 opts，不支持 name 的重置
 */
$.fn.initSelNum = function(opts){
    var el = $(this);
    opts = $.extend({
        name: '',// 组件生成的文本框的 name 值，定义后不可修改
        enable: true,// 初始化时是否启用
        allowEmpty: false,// 是否允许为 ''
        allowFloat: false,// 是否支持浮点数
        maxVal: Infinity,// 控件支持的最大值
        minVal: -Infinity,// 控件支持的最小值
        //value:''|0,// 初始化时的值
        step: 1,// 每次增减的数值
        onChange: $.noop// function(nCurVal, nOldVal) 值变化时的回调方法
    }, opts);
    var api;
    var jqTxt,
        bAllowEmpty, bAllowFloat, bEnable,// 是否允许空，是否允许浮点数，是否可用
        nInitVal,// 初始化时定义的默认值
        nMaxVal, nMinVal,// 设置的最大值和最小值
        nStep,
        nDefaultVal, nCurVal, nPreVal,// 初始化时设置的数值，当前数值，文本框显示''之前的数值
        aIptCode = [];// 允许输入的按键 code
    var fIsNumber = $.dataFormat.isNumber;

    var fReset = function(cusOpts){
        if(cusOpts){// 移除不支持修改的属性
            delete cusOpts.name;
        }
        $.extend(opts, cusOpts);
        /* 为全局变量赋值 */
        bAllowEmpty = opts.allowEmpty;
        bAllowFloat = opts.allowFloat;
        bEnable = opts.enable;
        nInitVal = opts.value;
        nMinVal = opts.minVal;
        nMaxVal = opts.maxVal;
        nStep = opts.step;
        // 允许输入的按键 code
        aIptCode.length = 0;
        aIptCode.push(37, 39, 8, 189, 109);// 左、右、退格、负号、负号(小键盘)
        if(bAllowFloat){
            aIptCode.push(190, 110);// 小数点、小数点(小键盘)
        }
        // TODO 判断 nInitVal, nMinVal, nMaxVal 的大小，做出错误提示
        nDefaultVal = nPreVal = fGetDefaultNum();
        nCurVal = undefined;
        fSetVal(nInitVal);// 为文本框赋初始值
        fSetEnable(bEnable);
    };
    // 初始化方法
    function fInit(){
        el.addClass('numbox');
        var str = '<input type="text" class="numbox-txt" ' + (opts.name ? 'name="' + opts.name + '"' : '') + ' value=""/>' +
            '<div class="numbox-wrap"><span class="numbox-up"></span><span class="numbox-down"></span></div>';
        el.append(str);
        jqTxt = el.find('.numbox-txt');
        el.find('.numbox-up, .numbox-down')
          .off('click.arrow')
          .on('click.arrow', fOnArrowClick);
        jqTxt.off('keydown.numSel change.numSel')
             .on('keydown.numSel', fOnIptKeydown)
             .on('change.numSel', fOnIptChange);
        fReset();
    }

    // 获取默认的数字值
    function fGetDefaultNum(){
        var val = 0;
        if(fIsNumber(nInitVal) === 'number'){
            val = nInitVal;
        }
        else if(nMinVal !== -Infinity){
            val = nMinVal;
        }
        else if(nMaxVal !== Infinity){
            val = nMaxVal;
        }
        return val;
    }

    var fSetEnable = function(enable){
        bEnable = enable;
        if(enable){// 启用
            el.removeClass('disabled');
            jqTxt.prop('disabled', false);
        }
        else{
            el.addClass('disabled');
            jqTxt.prop('disabled', true);
        }
    };

    // 获取当前的值
    function fGetVal(){
        return nCurVal;
    }

    // 为文本框赋值（先判断值是否合法）
    var fSetVal = function(val){
        var oldV = nCurVal;
        val += '';// 先强转为字符串
        val = bAllowFloat ? parseFloat(val) : parseInt(val, 10);
        if(fIsNumber(val)){// val 是数字
            if(val < nMinVal){// 判断是否超过最小值
                val = nMinVal;
            }
            else if(val > nMaxVal){
                val = nMaxVal;
            }
        }
        else{// val 非数字
            if(bAllowEmpty){// 允许为空
                val = '';
            }
            else{// 不允许为空
                val = fIsNumber(oldV) ? oldV : nDefaultVal;
            }
        }
        if(val + '' !== jqTxt.val().trim()){// 将 val 转换为字符串后与文本框内容比较
            jqTxt.val(val);
        }
        if(val !== oldV){// 值发生变化
            if(val === '' && fIsNumber(oldV)){// 前面的代码能保证 val = '' 时 bAllowEmpty 一定为 true，不需重复判断
                nPreVal = oldV;// 文本框显示 ''，记录 nPreVal，用于加减
            }
            nCurVal = val;
            if(oldV !== undefined){
                opts.onChange(nCurVal, oldV);// 调用回调
            }
        }
    };

    // 上下箭头点击函数
    function fOnArrowClick(event){
        if(!bEnable) return;
        var nBase = fIsNumber(nCurVal) ? nCurVal : nPreVal;
        fSetVal(fValAdd(nBase, $(this).hasClass('numbox-up') ? nStep : -nStep));
    }

    // 键盘抬起事件 - 将当前文本框内容值更新到组件
    function fOnIptChange(event){
        if(!bEnable) return;
        var iptVal = jqTxt.val();
        if(!bAllowEmpty && iptVal === ''){// 不允许为空的时候，文本框变为空
            fSetVal(nCurVal);
        }
        else{
            fSetVal(iptVal);
        }
    }

    // position=true => val+nStep; position=false => val-nStep
    var fValAdd = function(num1, num2){
        return bAllowFloat
            ? $.dataFormat.floatAdd(num1, num2)
            : num1 + num2;
    };

    // 键盘按下事件
    function fOnIptKeydown(event){
        if(!bEnable) return;
        var code = event.which;
        if(code == 38){// 加 step
            fSetVal(fValAdd(fIsNumber(nCurVal) ? nCurVal : nPreVal, nStep));
            event.preventDefault();// 阻止光标移动
        }
        else if(code == 40){// 减 step
            fSetVal(fValAdd(fIsNumber(nCurVal) ? nCurVal : nPreVal, -nStep));
            event.preventDefault();// 阻止光标移动
        }
        else if(code == 13){// 回车
            if(nCurVal === ''){
                return;
            }
            fSetVal(jqTxt.val());
        }
        else if(!(code >= 96 && code <= 105 || code >= 48 && code <= 57)
            && aIptCode.indexOf(code) === -1){
            return false;
        }
        // 数字按键引起的数据变化在 keyup 中执行
    }

    api = {
        setVal: fSetVal,
        getVal: fGetVal,
        setEnable: fSetEnable,
        fReset: fReset
    };
    /* 初始化开始 */
    fInit();
    return api;
};